package pri.zjy.matrix;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author zhangjy
 * @description 矩阵置零
 * <p>
 * 给定一个 m x n 的矩阵，如果一个元素为 0 ，则将其所在行和列的所有元素都设为 0 。请使用 原地 算法
 * <p>
 * 进阶：
 * <p>
 * 一个直观的解决方案是使用  O(mn) 的额外空间，但这并不是一个好的解决方案。
 * 一个简单的改进方案是使用 O(m + n) 的额外空间，但这仍然不是最好的解决方案。
 * 你能想出一个仅使用常量空间的解决方案吗？
 * @date 2025/3/7 15:54
 */
public class SetZeroes_73 {

    public static void main(String[] args) {

        int[][] matrix = new int[][]{{1, 1, 1}, {1, 0, 1}};
        SetZeroes_73 setZeroes73 = new SetZeroes_73();
        System.out.println(matrix.length);
        System.out.println(matrix[0].length);
        setZeroes73.setZeroes(matrix);
        System.out.println(matrix);
    }

    /**
     * 方法三：使用两个标记变量，使得S(n)=0(1)
     */
    public void setZeroes3(int[][] matrix) {

    }

    /**
     * 官解：标记数组
     * <p>
     * 我们可以用两个标记数组分别记录每一行和每一列是否有零出现。
     * <p>
     * 具体地，我们首先遍历该数组一次，如果某个元素为 0，那么就将该元素所在的行和列所对应标记数组的位置置为 true。最后我们再次遍历该数组，用标记数组更新原数组即可。
     * <p>
     * 复杂度分析：
     * <p>
     * 时间复杂度：O(mn)，其中 m 是矩阵的行数，n 是矩阵的列数。我们至多只需要遍历该矩阵两次。
     * <p>
     * 空间复杂度：O(m+n)，其中 m 是矩阵的行数，n 是矩阵的列数。我们需要分别记录每一行或每一列是否有零出现。
     * <p>
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     */
    public void setZeroes2(int[][] matrix) {
        boolean[] rows = new boolean[matrix.length];
        int colLength = matrix[0].length;
        boolean[] cols = new boolean[colLength];
        // 先标记为0元素的所在行、列
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < colLength; j++) {
                if (matrix[i][j] == 0) {
                    rows[i] = true;
                    cols[j] = true;
                }
            }
        }
        // 将所有标记下标元素置为0
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < colLength; j++) {
                if (rows[i] || cols[j]) {
                    matrix[i][j] = 0;
                }
            }
        }
    }

    /**
     * 个解：类似官解的标记数组，只是在把对应行、列置为0时更复杂
     * <p>
     * 分析：先找到哪些元素为0，再把对应行、列分别置为0，会遍历两次二维数组；
     * 二维数组matrix.length是指二维数组的行数，matrix[0].length才是二维数组的列数
     * <p>
     * 原地——>就是不能新建一个二维数组，而是在原二维数组基础上去操作；
     */
    public void setZeroes(int[][] matrix) {
        // 先记录所有为0元素下标
        Map<Integer, Integer> rowsMap = new HashMap<>();
        Map<Integer, Integer> columnsMap = new HashMap<>();

        int rows = matrix.length;
        if (rows < 0) return;
        int columns = matrix[0].length;
        if (columns < 0) return;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                if (matrix[i][j] == 0) {
                    rowsMap.put(i, i);
                    columnsMap.put(j, j);
                }
            }
        }

        // 再把这些下标对应行、列的所有元素置为0，做去重
        for (Map.Entry<Integer, Integer> entry : rowsMap.entrySet()) {
            for (int j = 0; j < columns; j++) {
                Integer i = rowsMap.get(entry.getKey());
                matrix[i][j] = 0;
            }
        }
        for (Map.Entry<Integer, Integer> entry : columnsMap.entrySet()) {
            for (int i = 0; i < rows; i++) {
                Integer j = columnsMap.get(entry.getKey());
                matrix[i][j] = 0;
            }
        }
    }

}
